package org.jsola.hr.service.impl;

import org.jsola.common.DateKit8;
import org.jsola.core.Page;
import org.jsola.exception.ParamException;
import org.jsola.hr.common.ExampleKit;
import org.jsola.hr.constant.HrConstants;
import org.jsola.hr.dao.IBookingsInfoDAO;
import org.jsola.hr.dto.BookingsInfoAddDTO;
import org.jsola.hr.dto.BookingsInfoUpdateDTO;
import org.jsola.hr.entity.BookingsBusinessDO;
import org.jsola.hr.entity.BookingsDatetimeDO;
import org.jsola.hr.entity.BookingsInfoDO;
import org.jsola.hr.provider.IMessageProviderService;
import org.jsola.hr.provider.IUserProviderService;
import org.jsola.hr.query.BookingsInfoQuery;
import org.jsola.hr.service.IBookingsBusinessService;
import org.jsola.hr.service.IBookingsDatetimeService;
import org.jsola.hr.service.IBookingsInfoService;
import org.jsola.hr.vo.BookingsInfoListVO;
import org.jsola.hr.vo.BookingsInfoVO;
import org.jsola.hr.vo.excel.BookingsInfoExportVO;
import org.jsola.message.dto.ShortMessageDTO;
import org.jsola.user.core.TokenUser;
import org.jsola.user.vo.UserVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import tk.mybatis.mapper.entity.Example;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import static org.jsola.user.constant.UserConstants.REGISTER_SCENE;

/**
 * 预约业务人员信息表
 *
 * @author zhr
 */
@Service("hrBookingsInfoServiceImpl")
public class BookingsInfoServiceImpl implements IBookingsInfoService {

    @Autowired
    private IBookingsInfoDAO bookingsInfoDAO;

    @Autowired
    private IBookingsBusinessService bookingsBusinessService;

    @Autowired
    private IBookingsDatetimeService bookingsDatetimeService;

    @Autowired
    private IMessageProviderService messageProviderService;

    @Autowired
    private IUserProviderService userProviderService;

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public BookingsInfoVO save(BookingsInfoAddDTO bookingsInfoAddDTO, TokenUser tokenUser) {
        ParamException.notNull(bookingsInfoAddDTO.getPhone(), "用户手机号未填写");
        ParamException.notNull(bookingsInfoAddDTO.getName(), "用户姓名未填写");
        ParamException.notNull(bookingsInfoAddDTO.getCaptcha(), "验证码未填写");
        // 校验验证码
        boolean checkCaptcha =
                messageProviderService.verifyCaptcha(REGISTER_SCENE, bookingsInfoAddDTO.getPhone(), bookingsInfoAddDTO.getCaptcha());
        if (!checkCaptcha) {
            throw new ParamException("验证码不正确");
        }
        // 看看这个人有约过没,约过走修改流程
        BookingsInfoDO bookingsInfo = selectByPhone(bookingsInfoAddDTO.getPhone());
        if (!ObjectUtils.isEmpty(bookingsInfo)) {
            BookingsInfoUpdateDTO bookingsInfoUpdateDTO = bookingsInfoAddDTO.to(BookingsInfoUpdateDTO.class);
            bookingsInfoUpdateDTO.setId(bookingsInfo.getId());
            bookingsInfoUpdateDTO.setOldBookingsDatetimeId(bookingsInfo.getBookingsDatetimeId());
            bookingsInfoUpdateDTO.setOldBusinessId(bookingsInfo.getBusinessId());
            int updateResult = update(bookingsInfoUpdateDTO, tokenUser);
            if (updateResult != 0) {
                BookingsInfoVO bookingsInfoVO = new BookingsInfoVO();
                bookingsInfoVO.setName(bookingsInfoUpdateDTO.getName());
                bookingsInfoVO.setPhone(bookingsInfoUpdateDTO.getPhone());
                bookingsInfoVO.setBookingsBusiness(bookingsInfoUpdateDTO.getBookingsBusiness());
                bookingsInfoVO.setServiceFall(bookingsInfoUpdateDTO.getServiceFall());
                bookingsInfoVO.setBookingsDay(bookingsInfoUpdateDTO.getBookingsDay());
                bookingsInfoVO.setBookingsDatetime(bookingsInfoUpdateDTO.getBookingsDatetime());
                return bookingsInfoVO;
            } else {
                throw new ParamException("修改失败,请重新发起预约");
            }
        }
        // 没有约过,走保存, 先注册一个user用户
        UserVO userVO = userProviderService.registerUser(bookingsInfoAddDTO.getName(), bookingsInfoAddDTO.getPhone());
        // 转DO
        BookingsInfoDO bookingsInfoDO = bookingsInfoAddDTO.to(BookingsInfoDO.class);
        bookingsInfoDO.setUserId(userVO.getId());
        // 保存
        bookingsInfoDO = save(bookingsInfoDO, tokenUser.getSiteId(), tokenUser.getUserId());
        // 保存的同时把 预约主表 和 预约时间段 的预约人数加一
        BookingsBusinessDO bookingsBusinessDO =
                bookingsBusinessService.selectDOById(bookingsInfoDO.getBusinessId(), tokenUser.getSiteId());
        bookingsBusinessDO.setBookingsRemainingCount(bookingsBusinessDO.getBookingsRemainingCount() + 1);
        bookingsBusinessService.updateByIdSelective(bookingsBusinessDO, tokenUser.getSiteId(), tokenUser.getUserId());

        BookingsDatetimeDO bookingsDatetimeDO =
                bookingsDatetimeService.selectDOById(bookingsInfoDO.getBookingsDatetimeId(), tokenUser.getSiteId());
        bookingsDatetimeDO.setBookingsDatetimeRemainingCount(bookingsDatetimeDO.getBookingsDatetimeRemainingCount() + 1);
        bookingsDatetimeService.updateByIdSelective(bookingsDatetimeDO, tokenUser.getSiteId(), tokenUser.getUserId());
        return bookingsInfoDO.to(BookingsInfoVO.class);
    }

    @Override
    public void sendBookingsMessage(String phone) {
        TokenUser tokenUser = new TokenUser();
        tokenUser.setSiteId("default");
        tokenUser.setUserId("system");
        ShortMessageDTO shortMessageDTO = new ShortMessageDTO();
        shortMessageDTO.setPhone(phone);
        shortMessageDTO.setScene(REGISTER_SCENE);
        messageProviderService.sendShortMessage(shortMessageDTO, tokenUser);
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public int update(BookingsInfoUpdateDTO bookingsInfoUpdateDTO, TokenUser tokenUser) {
        //转DO
        BookingsInfoDO bookingsInfoDO = bookingsInfoUpdateDTO.to(BookingsInfoDO.class);
        // 如果与原来的时间段或者业务不同,需要把原来的预约人数减一 当前修改的预约人数加一
        Long oldBookingsDatetimeId = bookingsInfoUpdateDTO.getOldBookingsDatetimeId();
        Long oldBusinessId = bookingsInfoUpdateDTO.getOldBusinessId();
        if (!bookingsInfoUpdateDTO.getBusinessId().equals(oldBusinessId)) {
            BookingsBusinessDO currentBookingsBusinessDO =
                    bookingsBusinessService.selectDOById(bookingsInfoDO.getBusinessId(), tokenUser.getSiteId());
            BookingsBusinessDO oldBookingsBusinessDO =
                    bookingsBusinessService.selectDOById(oldBusinessId, tokenUser.getSiteId());
            // 现在的加一
            currentBookingsBusinessDO.setBookingsRemainingCount(currentBookingsBusinessDO.getBookingsRemainingCount() + 1);
            // 以前的减一
            oldBookingsBusinessDO.setBookingsRemainingCount(oldBookingsBusinessDO.getBookingsRemainingCount() - 1);
            bookingsBusinessService.updateByIdSelective(currentBookingsBusinessDO, tokenUser.getSiteId(), tokenUser.getUserId());
            bookingsBusinessService.updateByIdSelective(oldBookingsBusinessDO, tokenUser.getSiteId(), tokenUser.getUserId());
        }
        if (!bookingsInfoUpdateDTO.getBookingsDatetimeId().equals(oldBookingsDatetimeId)) {
            BookingsDatetimeDO currentBookingsDatetimeDO =
                    bookingsDatetimeService.selectDOById(bookingsInfoDO.getBookingsDatetimeId(), tokenUser.getSiteId());
            BookingsDatetimeDO oldBookingsDatetimeDO =
                    bookingsDatetimeService.selectDOById(oldBookingsDatetimeId, tokenUser.getSiteId());
            // 现在的加一
            currentBookingsDatetimeDO.
                    setBookingsDatetimeRemainingCount(currentBookingsDatetimeDO.getBookingsDatetimeRemainingCount() + 1);
            // 以前的减一
            oldBookingsDatetimeDO.
                    setBookingsDatetimeRemainingCount(oldBookingsDatetimeDO.getBookingsDatetimeRemainingCount() + -1);
            bookingsDatetimeService.updateByIdSelective(currentBookingsDatetimeDO, tokenUser.getSiteId(), tokenUser.getUserId());
            bookingsDatetimeService.updateByIdSelective(oldBookingsDatetimeDO, tokenUser.getSiteId(), tokenUser.getUserId());
        }
        //根据主键更新，只更新非null值
        return updateByIdSelective(bookingsInfoDO, tokenUser.getSiteId(), tokenUser.getUserId());
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public int deleteByIds(TokenUser tokenUser, Long... bookingsInfoIds) {
        return logicalDeleteByIds(tokenUser.getSiteId(), tokenUser.getUserId(), (Object[]) bookingsInfoIds);
    }


    @Override
    public BookingsInfoVO selectById(Long bookingsInfoId, String siteId) {
        BookingsInfoDO bookingsInfoDO = selectDOById(bookingsInfoId, siteId);
        if (bookingsInfoDO == null) {
            return null;
        }
        return bookingsInfoDO.to(BookingsInfoVO.class);
    }

    @Override
    public BookingsInfoVO selectByUserId(TokenUser tokenUser) {
        Example example = new Example(BookingsInfoDO.class);
        example.and()
                .andEqualTo("valid", true)
                .andEqualTo("userId", tokenUser.getUserId());
        BookingsInfoDO bookingsInfoDO = bookingsInfoDAO.selectOneByExample(example);
        if (bookingsInfoDO == null) {
            return null;
        }
        return bookingsInfoDO.to(BookingsInfoVO.class);
    }

    @Override
    public List<BookingsInfoListVO> select(BookingsInfoQuery bookingsInfoQuery, String siteId) {
        List<BookingsInfoDO> bookingsInfoDOList = selectDO(bookingsInfoQuery, siteId);
        if (CollectionUtils.isEmpty(bookingsInfoDOList)) {
            return bookingsInfoDOList == null ? null : new ArrayList<>();
        }
        return bookingsInfoDOList.stream()
                .map(bookingsInfoDO -> bookingsInfoDO.to(BookingsInfoListVO.class))
                .collect(Collectors.toList());
    }

    @Override
    public int selectCount(BookingsInfoQuery bookingsInfoQuery, String siteId) {
        Example example = buildExample(bookingsInfoQuery, siteId);
        return bookingsInfoDAO.selectCountByExample(example);
    }

    @Override
    public Page<BookingsInfoListVO> selectPage(BookingsInfoQuery bookingsInfoQuery, String siteId) {
        Example example = buildExample(bookingsInfoQuery, siteId);
        Page<BookingsInfoDO> page = bookingsInfoDAO.selectPageByExample(example,
                bookingsInfoQuery.getPageNo(),
                bookingsInfoQuery.getPageSize());

        return page.to(BookingsInfoListVO.class);
    }

    @Override
    public BookingsInfoDO selectDOById(Long bookingsInfoId, String siteId) {
        return listById(bookingsInfoId, siteId);
    }

    @Override
    public List<BookingsInfoDO> selectDO(BookingsInfoQuery bookingsInfoQuery, String siteId) {
        Example example = buildExample(bookingsInfoQuery, siteId);
        return bookingsInfoDAO.selectByExample(example);
    }

    private BookingsInfoDO selectByPhone(String phone) {
        Example example = new Example(BookingsInfoDO.class);
        example.and()
                .andEqualTo("valid", true)
                .andEqualTo("phone", phone);
        return bookingsInfoDAO.selectOneByExample(example);
    }


    @Override
    public List<BookingsInfoExportVO> selectExportList(BookingsInfoQuery bookingsInfoQuery, String siteId) {
        List<BookingsInfoExportVO> resultList = new ArrayList<>();
        int count = selectCount(bookingsInfoQuery,siteId);
        if (count > 10000) {
            throw new ParamException("一次最多导出10000条数据，请缩小检索范围");
        }
        List<BookingsInfoDO> bookingsInfoDOList = selectDO(bookingsInfoQuery,siteId);
        if (CollectionUtils.isEmpty(bookingsInfoDOList)) {
            return new ArrayList<>();
        }
        bookingsInfoDOList.forEach(bookingsInfoDO->{
            BookingsInfoExportVO bookingsInfoExportVO = bookingsInfoDO.to(BookingsInfoExportVO.class);
            bookingsInfoExportVO.setBookingsDay(DateKit8.format2Date(bookingsInfoDO.getBookingsDay()));
            resultList.add(bookingsInfoExportVO);
        });
        return resultList;
    }
    /**
     * 根据查询参数，构建example
     *
     * @param bookingsInfoQuery 查询参数
     * @param siteId            所属站点id
     * @return example
     */
    private Example buildExample(BookingsInfoQuery bookingsInfoQuery, String siteId) {
        Example example = new Example(BookingsInfoDO.class);
        example.and()
                .andEqualTo("valid", true)
                .andEqualTo("siteId", siteId);
        // 排序
        ExampleKit.setExampleOrder(example, bookingsInfoQuery.getOrders());
        return example;
    }
}




